﻿//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2021 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

using System.Collections.Generic;
using UnityEngine;

namespace shaco.Base
{
    /// <summary>
    /// 游戏类全局接口管理中心
    /// </summary>
    public abstract class IGameHelper
    {
        /// <summary>
        /// 游戏管理器配置绝对路径
        /// </summary>
        static public string GameHelperConfigCurrentPath => System.IO.File.Exists(GameHelperConfigDownloadPath) ? GameHelperConfigDownloadPath : "{Project}/Resources/" + GameHelperConfigFileName;
        static public string GameHelperConfigInternalPath => string.Format("{0}/Base/Resources/{1}", shaco.Base.GlobalParams.GetShacoFrameworkRootPath(), GameHelperConfigFileName);
        static string GameHelperConfigDownloadPath => string.Format("{0}/{1}", Application.persistentDataPath, GameHelperConfigFileName);

        /// <summary>
        /// 游戏管理器配置文件名字
        /// </summary>
        static public string GameHelperConfigFileName
        {
            get { return "GameHelperConfig.bytes"; }
        }

        /// <summary>
        /// 游戏管理器配置对象
        /// </summary>
        static public shaco.Base.IDataSave gameConfig
        {
            get
            {
                if (null == _gameConfig)
                {
                    var configBytes = LoadConfigFromResources();
                    _gameConfig = new shaco.Base.DataSave();
                    if (null != configBytes)
                    {
                        _gameConfig.savePath = GameHelperConfigInternalPath;
                        _gameConfig.ReloadFromBytes(configBytes, false);

                        var checkKey = typeof(shaco.Base.IGameHelper).ToTypeString();
                        if (!_gameConfig.ContainsKey(checkKey))
                            gameConfig.WriteString(checkKey, typeof(shaco.Base.GameHelper).ToTypeString());
                        CheckInstance();
                    }
                    else
                    {
                        throw new System.IO.FileLoadException("not found game config data");
                    }
                }
                return _gameConfig;
            }
        }

        static private bool _isInited = false;
        static private shaco.Base.IDataSave _gameConfig = null;

        /// <summary>
        /// 框架初始化方法
        /// <return>初始化是否成功</return>
        /// </summary>
        virtual public void InitFramework()
        {
            shaco.Base.FileDefine.persistentDataPath = UnityEngine.Application.persistentDataPath;
        }

        /// <summary>
        /// 获取接口类
        /// <return>接口类</return>
        /// </summary>
        static public T GetOrSetDefaultInterface<T, DEFAULT>() where DEFAULT : class, IGameInstance where T : IGameInstance
        {
            var retValue = shaco.Base.GameEntry.TryGetInstance(typeof(T));
            if (null == retValue)
            {
                //从配置中读取自定义的接口类型
                if (null != gameConfig)
                {
                    var readTypeName = gameConfig.ReadString(typeof(T).ToTypeString());
                    if (!string.IsNullOrEmpty(readTypeName))
                    {
                        var instantiateTypeTmp = shaco.Base.Utility.Assembly.GetTypeWithinLoadedAssemblies(readTypeName);
                        if (null == instantiateTypeTmp)
                        {
                            // throw new System.ArgumentException("invalid type=" + readTypeName);
                            instantiateTypeTmp = typeof(DEFAULT);
                        }
                        shaco.Base.GameEntry.SetInstance(typeof(T), instantiateTypeTmp);
                        retValue = shaco.Base.GameEntry.GetInstance<T>();
                    }
                }

                //获取接口配置对应数据失败，使用默认接口类型
                if (null == retValue)
                {
                    shaco.Base.GameEntry.SetInstance<T, DEFAULT>();
                    retValue = shaco.Base.GameEntry.GetInstance<T>();
                }
            }
            return (T)retValue;
        }

        /// <summary>
        /// 获取接口类
        /// <return>接口类</return>
        /// </summary>
        static protected List<T> GetOrSetDefaultInterfaces<T>(System.Func<List<T>> callbackDefaultInterfaces) where T : IGameInstance
        {
            var typeKey = typeof(T);
            var retValue = shaco.Base.GameEntry.TryGetInstance(typeKey);
            if (null == retValue)
            {
                //从配置中读取自定义的接口类型
                if (null != gameConfig)
                {
                    var readTypeNames = gameConfig.ReadArrayString(typeKey.ToTypeString());
                    if (null != readTypeNames && readTypeNames.Length > 0)
                    {
                        var newListValue = new List<T>();
                        for (int i = 0; i < readTypeNames.Length; ++i)
                        {
                            var instantiateValue = shaco.Base.Utility.Instantiate(readTypeNames[i]);
                            if (null == instantiateValue || !instantiateValue.GetType().IsInherited(typeof(T)))
                                continue;

                            newListValue.Add((T)instantiateValue);
                        }
                        retValue = newListValue;

                        if (newListValue.Count > 0)
                            shaco.Base.GameEntry.SetInstanceValue(typeKey, newListValue);
                    }
                }
            }

            //获取接口配置对应数据失败，使用默认接口类型
            if (null == retValue)
            {
                shaco.Base.GameEntry.SetInstanceValue(typeKey, callbackDefaultInterfaces());
                retValue = shaco.Base.GameEntry.GetInstance<List<T>>();
            }
            return (List<T>)retValue;
        }

        /// <summary>
        /// 绑定接口实现类
        /// </summary>
        static protected void BindInterfaces<T>(object to)
        {
            if (null == to)
            {
                throw new System.Exception("GameHelper BindInterfaces error: valid param, from=" + typeof(T) + " to=" + to);
            }
            shaco.Base.GameEntry.SetInstanceValue(typeof(T), to);
        }

        /// <summary>
        /// 绑定接口实现类
        /// </summary>
        static protected void BindInterface<T>(object to)
        {
            if (null == to)
            {
                throw new System.Exception("GameHelper BindInterface error: valid param, from=" + typeof(T) + " to=" + to);
            }
            shaco.Base.GameEntry.SetInstance(typeof(T), to.GetType());
        }

        /// <summary>
        /// 检查管理器的实例化
        /// </summary>
        static private void CheckInstance()
        {
            if (!_isInited)
            {
                _isInited = true;
                var gameHelperType = _gameConfig.ReadString(typeof(IGameHelper).FullName, typeof(shaco.Base.GameHelper).FullName);
                var gameHelper = (IGameHelper)shaco.Base.Utility.Instantiate(gameHelperType);
                gameHelper.InitFramework();
            }
        }

        /// <summary>
        /// 读取配置文件二进制数据
        /// <return>配置文件二进制数据</return>
        /// </summary>
        static private byte[] LoadConfigFromResources()
        {
            byte[] retValue = null;

#if UNITY_EDITOR
            //编辑器直接读取本地文件可以防止AssetDatabase没有及时刷新导致配置读取失败的bug
            if (!System.IO.File.Exists(GameHelperConfigInternalPath))
            {
                System.IO.File.Create(GameHelperConfigInternalPath);
                UnityEditor.AssetDatabase.ImportAsset(GameHelperConfigInternalPath);
            }
#endif
            //优先读取本地下载目录中的配置
            if (System.IO.File.Exists(GameHelperConfigDownloadPath))
                retValue = System.IO.File.ReadAllBytes(GameHelperConfigDownloadPath);
            
            //读取本地Resources目录
            if (null == retValue || 0 == retValue.Length)
            {
                var assetLoaded = UnityEngine.Resources.Load<UnityEngine.TextAsset>(shaco.Base.FileHelper.RemoveAllExtentsion(GameHelperConfigFileName));
                retValue = null == assetLoaded ? null : assetLoaded.bytes;
                // Debug.Log("Load shaco framework config from 'Resources'");
            }
            else
                Debug.Log("Load shaco framework config from=" + GameHelperConfigDownloadPath);

            //禁止使用shaco框架中的内容进行加载，否则很容易导致死循环！！！
            // retValue = shaco.Base.FileHelper.ReadAllByteByUserPath(GameHelperConfigPath);

            //加载失败
            if (null == retValue)
                throw new System.Exception("IGameHelper LoadConfigFromResources error: path=" + GameHelperConfigFileName);
            return retValue;
        }
    }
}